package com.ns.sbs.oauth.minio.conf;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.ns.core.current.config.SymbolsMark;
import com.ns.sbs.oauth.minio.vo.MinioItemVO;
import io.minio.*;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * minio 处理层
 *
 * @author lw
 * @since 2023/11/22
 */
@Component
@RequiredArgsConstructor
public class MinioTemplate {

    private static final Logger LOGGER = LoggerFactory.getLogger(MinioTemplate.class);

    private final MinioClient minioClient;

    @Value("${minio.bucket}")
    public String bucketName;

    @Value("${minio.server}")
    public String server;

    @Value("${minio.port}")
    public String port;

    /**
     * 判断bucket是否存在，不存在则创建
     *
     * @param name 桶名
     */
    public void existBucket(String name) {
        try {
            boolean exist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
            if (!exist) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(name).build());
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 创建存储bucket
     *
     * @param bucketName 存储bucket名称
     * @return Boolean
     */
    public Boolean makeBucket(String bucketName) {
        try {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            return true;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 删除存储bucket
     *
     * @param bucketName 存储bucket名称
     * @return Boolean
     */
    public Boolean removeBucket(String bucketName) {
        try {
            minioClient.removeBucket(RemoveBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
            return true;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 文件上传
     *
     * @param mf 文件对象
     * @return
     */
    public MinioItemVO upload(MultipartFile mf) {
        MinioItemVO file = new MinioItemVO();
        try {
            String newFileName = MinioFileUtils.extractUploadFilename(mf);
            // 上传到minio服务器
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(this.bucketName)
                    .object(newFileName)
                    .stream(mf.getInputStream(), -1L, 10485760L)
                    .build());
            file.setName(newFileName);
            file.setSize(mf.getSize());
            file.setOriginName(mf.getOriginalFilename());
            file.setType(mf.getContentType());
            file.setUrl(server + SymbolsMark.COLON + port + StringPool.SLASH + bucketName + StringPool.SLASH + newFileName);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return file;
    }

    /**
     * 文件下载
     *
     * @param fileName 文件名
     * @param delete   是否删除
     * @throws IOException
     */
    public void fileDownload(@RequestParam(name = "fileName") String fileName,
                             @RequestParam(defaultValue = "false") Boolean delete,
                             HttpServletResponse response) {

        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            if (!StringUtils.hasText(fileName)) {
                response.setHeader("Content-type", "text/html;charset=UTF-8");
                String data = "文件下载失败";
                OutputStream ps = response.getOutputStream();
                ps.write(data.getBytes("UTF-8"));
                return;
            }

            outputStream = response.getOutputStream();
            // 获取文件对象
            inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(this.bucketName).object(fileName).build());
            byte buf[] = new byte[1024];
            int length = 0;
            response.reset();
            response.setHeader("Content-Disposition", "attachment;filename=" +
                    URLEncoder.encode(fileName.substring(fileName.lastIndexOf("/") + 1), "UTF-8"));
            response.setContentType("application/octet-stream");
            response.setCharacterEncoding("UTF-8");
            // 输出文件
            while ((length = inputStream.read(buf)) > 0) {
                outputStream.write(buf, 0, length);
            }
            inputStream.close();
            // 判断：下载后是否同时删除minio上的存储文件
            if (delete) {
                minioClient.removeObject(RemoveObjectArgs.builder().bucket(this.bucketName).object(fileName).build());
            }
        } catch (Throwable ex) {
            response.setHeader("Content-type", "text/html;charset=UTF-8");
            String data = "文件下载失败";
            try {
                OutputStream ps = response.getOutputStream();
                ps.write(data.getBytes("UTF-8"));
            } catch (IOException e) {
                throw new RuntimeException(e.getMessage());
            }
        } finally {
            try {
                outputStream.close();
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e.getMessage());
            }
        }
    }


    /**
     * 查看文件对象
     *
     * @param bucketName 存储bucket名称
     * @return 存储bucket内文件对象信息
     */
    public List<MinioItemVO> listObjects(String bucketName) {
        Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).build());
        List<MinioItemVO> minioItems = new ArrayList<>();
        try {
            for (Result<Item> result : results) {
                Item item = result.get();
                MinioItemVO mom = new MinioItemVO();
                mom.setName(item.objectName());
                mom.setSize(item.size());
                minioItems.add(mom);
            }
            return minioItems;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 批量删除文件对象
     *
     * @param bucketName 存储bucket名称
     * @param objects    对象名称集合
     */
    public Boolean removeObjects(String bucketName, List<String> objects) {
        Map<String, String> resultMap = new HashMap<>();
        List<DeleteObject> dos = objects.stream().map(e -> new DeleteObject(e)).collect(Collectors.toList());
        try {
            minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(dos).build());
            return true;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }
}


